package ThreadDemo.ThreadDemo4;

/**
 *
 * Created with IntelliJ IDEA.
 * Description:
 * User:周次煜
 * Date: 2024-07-18
 * Time：21:29
 *
 */


public class SynchronizedDemo {

    /**
     * 死锁的情况:
     *
     *  自己重复锁
     *
     *  Java 自身的机制 就会做出标志 , 内部的就不会再次对相同的对象进行上锁
     *  所以 不会出现重复锁的现象
     *
     *  从第一个 { 开始加锁
     *
     *  当出现最后一个 } 时,就意味着要解锁了
     *
     */

    public  static  int count = 0;


    static class  Counter {



        synchronized public void countAdd() {
            count++;
        }

    }


    public static void main(String[] args) throws InterruptedException {


        Counter counter = new Counter();

        Thread t1 = new Thread(()-> {

            for (int i = 0; i < 50000; i++) {

                synchronized(counter) {
                    counter.countAdd();
                }

            }


        });


        Thread t2 = new Thread(()-> {


            for (int i = 0; i < 50000; i++) {

                synchronized (counter) {
                    counter.countAdd();
                }

            }


        });


         t1.start();
         t2.start();

         t1.join();
         t2.join();


        System.out.println(count);

    }


}


/**
 * 死锁第二种情况
 * 两个线程 和 两个对象
 *
 * 先让线程1 去抢 锁对象1
 * 然后再嵌套 锁对象2
 *
 * 同时线程2 抢锁对象 2
 * 然后线程2 抢锁对象 1
 *
 * 这样的就会造成 线程1 锁住对象1
 * 线程2 锁住对象2
 *
 * 当同时再抢想锁对方的锁时就会造成死锁的情况
 *
 */


class  SynchronizedTest1 {


    // 创建锁对象
    public  static   Object locker1 = new Object();
    public static Object locker2 = new Object();


    public static void main(String[] args) {
        Thread t1= new Thread(()->{
           synchronized(locker1) {
               System.out.println("t1对锁对象locker1 加锁!");
               synchronized(locker2) {
                   System.out.println("t1对锁对象locker2 加锁!");

               }


               // locker1 开锁标志
           }
        });


        Thread t2= new Thread(()->{
            synchronized(locker2) {
                System.out.println("t2对锁对象locker2 加锁!");
                synchronized(locker1) {
                    System.out.println("t2对锁对象locker1 加锁!");

                }

//                locker2 开锁标志
            }
        });


        t1.start();
        t2.start();
    }
}


/**
 *
 * 防止死锁的解决方案
 *
 * 1. 去除锁之间的嵌套的情况
 *
 * 方案一: 减少同时两个锁对象嵌套的情况
 * 1. 这样可以有效的把 对象1 进行加锁后解锁后,还能继续给别的线程进行加锁
 * 2. 不会出现相互阻塞的情况,当一个线程给一个对象加锁时,
 *
 *
 */


class  SynchronizedTest2 {

    // 创建锁对象
    public  static   Object locker1 = new Object();
    public static Object locker2 = new Object();

    public static void main(String[] args) {
        Thread t1= new Thread(()->{
            synchronized(locker1) {
                System.out.println("t1对锁对象locker1 加锁!");

                // locker1 开锁标志
            }


            synchronized(locker2) {
                System.out.println("t1对锁对象locker2 加锁!");

//                locker2 开锁标志
            }
        });


        Thread t2= new Thread(()->{
            synchronized(locker2) {
                System.out.println("t2对锁对象locker2 加锁!");


//                locker2 开锁标志
            }


            synchronized(locker1) {
                System.out.println("t2对锁对象locker1 加锁!");

                // locker1 开锁标志
            }
        });


        t1.start();
        t2.start();
    }
}


/**
 * 防止死锁方案二: 按一定的次序上锁进行上锁
 *按一定的次序上锁, 一边运行, 一边阻塞 ,形成一定的次序
 * 不用像之前那样相互缠绕而形成 死循环,对方阻挡着对方的路,这样就都无法进行.
 */


class  SynchronizedTest3 {


    // 创建锁对象
    public  static   Object locker1 = new Object();
    public static Object locker2 = new Object();


    public static void main(String[] args) {
        Thread t1= new Thread(()->{
            synchronized(locker1) {
                System.out.println("t1对锁对象locker1 加锁!");
                synchronized(locker2) {
                    System.out.println("t1对锁对象locker2 加锁!");

                }


                // locker1 开锁标志
            }
        });


        Thread t2= new Thread(()->{
            synchronized(locker1) {
                System.out.println("t2对锁对象locker1 加锁!");
                synchronized(locker2) {
                    System.out.println("t2对锁对象locker2 加锁!");

                }

//                locker1 开锁标志
            }
        });


        t1.start();
        t2.start();
    }
}







